<?php
////////////////////////////////////////////////////////////////////////////////
//	  This file is part of PushLMS.
//
//    PushLMS is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    PushLMS is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with PushLMS.  If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////

class AsessionsController extends AppController {

	var $scaffold = 'admin';
	var $uses = array('Asession', 'Asessionlog', 'Asessionresult', 'Course', 'User', 'Assessment', 'Questiongroup', 'Question', 'Answer');
	var $helpers = array('Form', 'Javascript', 'Ajax', 'Xml', 'Paginator');
	
	var $paginate = array(
              'limit' => 9,
              'order' => array(
                'Asession.created' => 'asc'
                )
              );

	var $asession_id = false;

	function beforeFilter() {
	
		$this->layout = 'none';

		$this->Auth->allow('index');
		$this->Auth->allow('begin');
		$this->Auth->allow('state');
		$this->Auth->allow('question');
		$this->Auth->allow('question_xml');
		$this->Auth->allow('message');
		$this->Auth->allow('message_xml');
		$this->Auth->allow('questiongroup');
		$this->Auth->allow('questiongroup_xml');
		$this->Auth->allow('student_number');
		$this->Auth->allow('answer');
		$this->Auth->allow('assessment');
		$this->Auth->allow('assessment_xml');
		$this->Auth->allow('check');
		$this->Auth->allow('clear');
	}

	function display()
	{
		$this->layout = 'default';

		$assessments = $this->Assessment->find('list');
		$this->set('assessments', $assessments);
	}
	
	function results()
	{
		$this->layout = 'default';

		error_log('got data'.print_r($this->data,true));
		$assessment_id = 0;
		if(empty($this->data))
			$assessment_id = $this->Session->read('assessment_id');
		else
			$assessment_id =$this->data['Asession']['Assessment'];
		
		$data = $this->paginate('Asession', array('Asession.assessment_id' => $assessment_id));
		
		$this->set('data', $data);

		if(!empty($this->data))
		{
			$this->Session->write('assessment_id', $this->data['Asession']['Assessment']);
			if ($this->data['Asession']['download_csv'])
			{
				Configure::write('debug', 0); 
				$assessment_id = $this->data['Asession']['Assessment'];
				$asessions = $this->Asession->find('all',
					array(
						'conditions' => array('Asession.assessment_id' => $assessment_id),
						//'recursive' => 2,
					)
				);
				$this->set('asessions', $asessions);
				$this->header("Content-type: application/csv");
				$this->header("Content-Disposition: \"inline; filename=results.csv;\"");
				$this->layout = 'none';
				$this->render('display_csv');
				
			}
		}

		$assessments = $this->Assessment->find('list');
		$this->set('assessments', $assessments);
	}

	function ajax_get($id=null)
	{
		$asessions = $this->Asession->find('all',
			array(
				'conditions' => array('Asession.id' => $id),
				'recursive' => 2,
			)
		);
		
		$new_asessions = array();
		$i = 0;
		foreach ($asessions as $asession)
		{
			foreach ($asession['Asessionlog'] as $key => $value)
			{
				if ($asession['Asessionlog'][$key]['answer'] > 0)
				{
					$answer = $this->Answer->findById($asession['Asessionlog'][$key]['Asessionresult'][0]['answer_id']);
					$asession['Asessionlog'][$key]['AnswerGiven'] = $answer;
				}
			}
			$new_asessions[] = $asession;
		}
		$new_assession;
		foreach($new_asessions as $val)
		{
			if($id == $val['Asession']['id'])
			{
				$new_asession = $val;
			}
		}

		$this->set('asession', $new_asession);
	}

	################
	# PUBLIC DISPLAY METHODS
	################

	function assessment_xml($token, $assessment_id){
		$this->assessment($token,$assessment_id);
		$this->header('Content-Type: text/xml');
		$this->layout = 'none';
		$this->render('assessment_xml');
	}

	function assessment($token, $assessment_id){

		// ensure that the method is GET only for REST compliance
		if (!$this->RequestHandler->isGet()){
			#error_log('/asessions/question must be of method GET');
			$this->set('message', 'INVALID HTTP REQUEST METHOD: expected GET');
			$this->header('HTTP/1.1 400 Bad Request');
			$this->render('index');
			return;
		}

		if ($this->_validate_token($token)){

			$this->layout = 'notepad';

			if (@env('HTTPS') == 'on'){
				$protocol = 'https://';
			}else{
				$protocol = 'http://';
			}

			$this->set('base_url',$protocol.env('SERVER_NAME'));
			
			$this->Assessment->unbindModel(
				array('hasMany' => array('Asession'))
			);
			$this->Assessment->unbindModel(
				array('hasMany' => array('Asessionlog'))
			);
			$this->Assessment->Questiongroup->unbindModel(
				array('belongsTo' => array('Assessment'))
			);
			$this->Assessment->Questiongroup->Question->Answer->unbindModel(
				array('hasMany' => array('Asessionresult'))
			);

			$assessment = $this->Assessment->find('first',
				array(
					'conditions' => array('Assessment.id' => $assessment_id),
					'recursive' => 3, 					
				)
			);

			if (!empty($assessment)){
				
				$newSessionLog = array(
					'Asessionlog' => array(
						'asession_id' => $this->asession_id,
						'message' => 'List Assessment',
						'questiongroup_id' => 0,
						'correct' => 1,
						'answer' => 0,
						'question_id' => 0
					),
				);

				$this->Asessionlog->save($newSessionLog);
				unset($this->Asessionlog->id);


				$this->set('assessment', $assessment);
				$this->set('token', $token);
			
			}

		}else{

			$this->redirect('/asessions/index');

		}

	}

	function index(){

		$this->header('HTTP/1.1 401 Unauthorized');
		$this->header('Content-Type: text/xml'); 
		$this->set('message', 'invalid assessment token supplied. Please restart your assessment');

	}

	function question_xml($token, $question_id){
		$this->question($token,$question_id);
		$this->header('Content-Type: text/xml');
		$this->layout = 'none';
		$this->render('question_xml');
	}

	function question($token, $question_id){

		// ensure that the method is GET only for REST compliance
		if (!$this->RequestHandler->isGet()){
			#error_log('/asessions/question must be of method GET');
			$this->set('message', 'INVALID HTTP REQUEST METHOD: expected GET');
			$this->header('HTTP/1.1 400 Bad Request');
			$this->render('index');
			return;
		}

		if ($this->_validate_token($token)){

			$this->layout = 'notepad';

			$this->Question->unbindModel(
				array('hasMany' => array('Asessionlog'))
			);
			$this->Question->Questiongroup->unbindModel(
				array('hasMany' => array('Asessionlog'))
			);
			$this->Question->Answer->unbindModel(
				array('hasMany' => array('Asessionresult'))
			);

			$question = $this->Question->find('first',
				array(
					'conditions' => array('Question.id' => $question_id),
					'recursive' => 2, 
				)
			);

			if (!empty($question)){
				
				$newSessionLog = array(
					'Asessionlog' => array(
						'asession_id' => $this->asession_id,
						'questiongroup_id' => 0,
						'correct' => 1,
						'answer' => 0,
						//'message' => 'Question Displayed',
						'question_id' => $question['Question']['id']
					),
				);

				$this->Asessionlog->save($newSessionLog);
				unset($this->Asessionlog->id);

				if ($question['Question']['random_answers'] == 1){
					$question['Answer'] = $this->_randomise_answers($question);
				}

				$this->set('question', $question);
				$this->set('token', $token);
			
			}

		}else{
			$this->redirect('/asessions/index');
		}
	}

	function message_xml($token, $questiongroup_id){
		$this->message($token, $questiongroup_id);
		$this->header('Content-Type: text/xml');
		$this->layout = 'none';
	}	

	function message($token, $questiongroup_id){

		// ensure that the method is GET only for REST compliance
		if (!$this->RequestHandler->isGet()){
			#error_log('/asessions/message must be of method GET');
			$this->set('message', 'INVALID HTTP REQUEST METHOD: expected GET');
			$this->header('HTTP/1.1 400 Bad Request');
			$this->render('index');
			return;
		}

		if ($this->_validate_token($token)){

			$this->layout = 'notepad';

			$this->Questiongroup->unbindModel(
				array('hasMany' => array('Asessionlog'))
			);			

			$questiongroup = $this->Questiongroup->findById($questiongroup_id);

			if (!empty($questiongroup)){
				$this->set('questiongroup', $questiongroup);
				$this->set('token', $token);
			}

			$newSessionLog = array(
				'Asessionlog' => array(
					'asession_id' => $this->asession_id,
					'questiongroup_id' => $questiongroup['Questiongroup']['id'],
					'correct' => 1,
					'question_id' => 0,
					'answer' => 0,
					'event_id' => 0,
					'message' => ''
					//'message' => 'Message Displayed'
				),

			);

			$this->Asessionlog->save($newSessionLog);
			unset($this->Asessionlog->id);

		}else{

			$this->redirect('/asessions/index');

		}

	}

	function questiongroup_xml($token, $questiongroup_id){
		$this->questiongroup($token, $questiongroup_id);
		$this->layout = 'none';
		$this->header('Content-Type: text/xml');
	}

	function questiongroup($token, $questiongroup_id){
		
		// ensure that the method is GET only for REST compliance
		if (!$this->RequestHandler->isGet()){
			#error_log('/asessions/questiongroup must be of method GET');
			$this->set('message', 'INVALID HTTP REQUEST METHOD: expected GET');
			$this->header('HTTP/1.1 400 Bad Request');
			$this->render('index');
			return;
		}

		if ($this->_validate_token($token)){
			
			$this->layout = 'notepad';

			$this->Questiongroup->unbindModel(
				array('hasMany' => array('Asessionlog'))
			);			

			$questiongroup = $this->Questiongroup->findById($questiongroup_id);

			if (!empty($questiongroup)){
				$this->set('questiongroup', $questiongroup);
				$this->set('token', $token);
			}

			$newSessionLog = array(
				'Asessionlog' => array(
					'asession_id' => $this->asession_id,
					'questiongroup_id' => $questiongroup['Questiongroup']['id'],
					'correct' => 0,
					'question_id' => 0,
					'answer' => 0,
					'event_id' => 0,
					'message' => ''
					//'message' => 'Question Group START'
				),

			);

			$this->Asessionlog->save($newSessionLog);
			unset($this->Asessionlog->id);

		}else{

			$this->redirect('/asessions/index');

		}

	}

	################
	# PUBLIC INTERFACE METHODS
	################

	function begin(){

		// ensure that the method is POST only for REST compliance
		if (!$this->RequestHandler->isPost()){
			#error_log('begin must be of method POST');
			$this->set('message', 'INVALID HTTP REQUEST METHOD: expected POST');
			$this->header('HTTP/1.1 400 Bad Request');				
			$this->Asessionlog->save($newSessionLog);
			unset($this->Asessionlog->id);
			$this->render('index');
			return;
		}

		if (!$this->_validate_auth_header()){
			#error_log('unauthorised');
			$this->set('message', 'INVALID AUTH DATA: invalid auth header supplied');
			$this->header('HTTP/1.1 400 Bad Request');
			$this->render('index');
			return;
		}
		
		if(!$this->_authenticate($this->data['Request']['Auth']['assessment'], $this->data['Request']['Auth']['password'])){

			#error_log('failed to authenticate');
			$this->set('message','failed to authenticate');
			$this->header('HTTP/1.1 401 Unauthorized');
			$this->render('index');
			
		}else{
			
			$token = $this->_gen_assessment_key();

			#error_log('after gen:'.$token);

			$newSession = array(
				'Asession' => array(
					'uniqueid' => $token,
					'assessment_id' => $this->data['Request']['Auth']['assessment'],
					'course_id' => $this->data['Request']['Auth']['course'],
					'username' => $this->data['Request']['Auth']['username'],
					'result' => 0,
					'complete' => 0
				),
			);

			if (isset($this->data['Request']['Auth']['student_number'])){
				$newSession['Asession']['student_number'] = $this->data['Request']['Auth']['student_number'];
			}

			$this->Asession->save($newSession);
			$this->asession_id = $this->Asession->id;
			unset($this->Asession->id);

			$newSessionLog = array(
				'Asessionlog' => array(
					'asession_id' => $this->asession_id,
					'questiongroup_id' => 0,
					'correct' => 0,
					'question_id' => 0,
					'answer' => 0,
					'event_id' => 0,
					'message' => ''
					//'message' => 'New Assessment Session Created'
				),
			);

			$this->Asessionlog->save($newSessionLog);
			unset($this->Asessionlog->id);

			if (@env('HTTPS') == 'on'){
				$protocol = 'https://';
			}else{
				$protocol = 'http://';
			}

			$this->set('token', $token);
			$this->set('state', 'begin');
			$this->set('message', 'Assessment Session Started');
			$this->set('state_url', $protocol.env('SERVER_NAME').'/asessions/state/'.$token);

			$this->header('HTTP/1.1 200 OK');
			$this->header('Content-Type: text/xml');

		}

	}

	function check($token, $question_id){

		if ($this->_validate_token($token)){

			$this->set('token', $token);

			$this->header('Content-Type: text/xml');

			$question = $this->Question->findById($question_id);

			
				$asessionlog = $this->Asessionlog->find('first',
					array(
						'conditions' => array(
							'Asessionlog.asession_id' => $this->asession_id, 
							'Asessionlog.answer' => $question_id,
							'Asessionlog.correct' => 1
						),
						'recursive' => 2
					)
				);

				if (!empty($asessionlog)){

					$this->set('token', $token);
					$this->set('status', 'true');
					$this->set('actionName', $question['Question']['action']);
					$this->set('asessionlog', $asessionlog);

				}else{

					$this->set('token', $token);
					$this->set('status', 'false');
					$this->set('actionName', $question['Question']['action']);
					$this->set('asessionlog', array());

				}
				
		}
	}

	function clear($token){
		
		// ensure that the method is GET only for REST compliance
		if (!$this->RequestHandler->isGet()){
			#error_log('/asessions/questiongroup must be of method GET');
			$this->set('message', 'INVALID HTTP REQUEST METHOD: expected GET');
			$this->header('HTTP/1.1 400 Bad Request');
			$this->render('index');
			return;
		}

		if ($this->_validate_token($token)){

			$asession = $this->Asession->findById($this->asession_id);

			foreach ($asession['Asessionlog'] as $asessionlog){
				$this->Asessionlog->delete($asessionlog['id']);
				$asessionresults = $this->Asessionresult->findById($asessionlog['id']);
				foreach ($asessionlog['Asessionresult'] as $asessionresult){
					$this->Asessionresult->delete($asessionresult['id']);
				}
			}

			$this->set('message',$token.' results cleared');

		}else{

			$this->redirect('/asessions/index');

		}

		$this->header('Content-Type: text/xml');

	}
	
	function state($token, $local = false, $redirect = true){

		if ($local === false){

			// ensure that the method is GET only for REST compliance
			if (!$this->RequestHandler->isGet()){
				#error_log('state must be of method GET');
				$this->set('message', 'INVALID HTTP REQUEST METHOD: expected GET');
				$this->header('HTTP/1.1 400 Bad Request');
				$this->render('index');
				return;
			}
		
		}

		if ($this->_validate_token($token)){

			if (@env('HTTPS') == 'on'){
				$protocol = 'https://';
			}else{
				$protocol = 'http://';
			}

			$this->set('token', $token);

			if ($this->_has_student_number()){

				$data = $this->next();

				$state_url = false;

				if ($data['state'] == 'questiongroup'){

					$this->set('message', $data['questiongroup']['Questiongroup']['description']);
					$this->set('action', $data['questiongroup']['Questiongroup']['action']);

					if ($data['questiongroup']['Questiongroup']['message_only'] == 1){
						
						$state_url = $protocol.env('SERVER_NAME').'/asessions/message/'.$token.'/'.$data['questiongroup']['Questiongroup']['id'];
						$state_xmlurl = $protocol.env('SERVER_NAME').'/asessions/message_xml/'.$token.'/'.$data['questiongroup']['Questiongroup']['id'];

						$this->set('url', $state_url);	
						$this->set('xmlurl', $state_xmlurl);
						$this->set('state', 'message');
					
					}else{
					
						$state_url = $protocol.env('SERVER_NAME').'/asessions/questiongroup/'.$token.'/'.$data['questiongroup']['Questiongroup']['id'];
						$state_xmlurl = $protocol.env('SERVER_NAME').'/asessions/questiongroup_xml/'.$token.'/'.$data['questiongroup']['Questiongroup']['id'];

						$this->set('url', $state_url);	
						$this->set('xmlurl', $state_xmlurl);
						$this->set('state', 'questiongroup');
					
					}

				}
				elseif ($data['state'] == 'question'){
					
					$this->header('HTTP/1.1 200 Ok');
				
					$state_url = $protocol.env('SERVER_NAME').'/asessions/question/'.$token.'/'.$data['question']['Question']['id'];
					$state_xmlurl = $protocol.env('SERVER_NAME').'/asessions/question_xml/'.$token.'/'.$data['question']['Question']['id'];

					$this->set('message', $data['question']['Question']['name']);
					$this->set('action', $data['question']['Question']['action']);
					$this->set('xmlurl', $state_xmlurl);
					$this->set('url', $state_url);	
					$this->set('state', 'question');

				}
				elseif ($data['state'] == 'complete'){

					$this->header('HTTP/1.1 200 Ok');

					$this->set('message', 'Assessment is Complete');
					$this->set('action', 'false');
					$this->set('url', 'false');
					$this->set('xmlurl', 'false');
					$this->set('state', 'complete');

				}else{

					$this->header('HTTP/1.1 500 Internal Server Error');

					$this->set('message', 'State Error');
					$this->set('action', 'false');
					$this->set('url', 'false');
					$this->set('xmlurl', 'false');
					$this->set('state', 'error');				

				}

			}else{

				$state_url = $protocol.env('SERVER_NAME').'/asessions/student_number/'.$token;
				$state_xmlurl = $protocol.env('SERVER_NAME').'/asessions/student_number/'.$token;

				$this->set('url', $state_url);	
				$this->set('action', 'false');
				$this->set('xmlurl', $state_xmlurl);
				$this->set('state', 'student_number');
				$this->set('message', 'Student Must Enter Student Number To Continue');

			}


			
		}else{

			$this->redirect('/asessions/index');

		}

		$this->header('HTTP/1.1 200 OK');

		if ($local == false){
			$this->header('Content-Type: text/xml');
		}else{
			if ($state_url != false){
				if ($redirect === true){
					if ($data['state'] == 'question'){
						$this->redirect($state_url);
					}
				}
				elseif($redirect == 'return'){
					return $state_url;
				}
			}
		}

	}

	function student_number($token = false, $student_number = false){
			
		/* 

		no HTTP Method check here. Should be PUT really
		perhaps a different method could be used to display
		the form that can be used to POST the student number
		or this method could check 2 different HTTP methods
		when called in different ways.
		
		This is due to be changed in a future release 
		and a PUT method will be applied to it.
		The documentation needs to be changed to reflect this

		*/

		#error_log($token.' / '.$student_number);

		$this->layout = 'notepad';
		$this->set("CSS", "main");

		if (!empty($this->data)){

			#error_log('got data'.print_r($this->data,true));

			if (empty($this->data['Asession']['student_number'])){
				#error_log("student_number has not been supplied");
				$this->Session->setFlash("Student Number has not been supplied");
				$this->redirect('/asessions/student_number/'.$this->data['Asession']['token']);
			}
			
		}

		elseif (($token == false) &&  ($student_number == false)){
			$this->set('message', 'INVALID PATH: missing arguments');
			$this->header('HTTP/1.1 400 Bad Request');
			$this->render('index');
			return;
		}

		if (empty($this->data)){
			
			$this->data['Asession'] = array(
				'token'=> $token,
				'student_number' => $student_number
			);

		}

		if ($this->_validate_token($this->data['Asession']['token'])){

			$this->set('added',false);

			if (!empty($this->data['Asession']['student_number'])){

				#error_log($this->data['Asession']['student_number']);

				$this->Asession->id = $this->asession_id;

				#error_log($this->Asession->id);

				$this->Asession->saveField('student_number',$this->data['Asession']['student_number']);
				$this->Session->setFlash("Student Number Supplied");
				$this->set('added',true);

			}else{

				$this->Session->setFlash("Please Supply Student Number");

			}

			$this->set('token', $this->data['Asession']['token']);

		}else{

			$this->redirect('/asessions/index');

		}

	}

	function answer($token = false, $question_id = false, $answer_id=false){

		# should put a REST GET / PUT check in this method.

		$this->layout = 'notepad';
		$this->set("CSS", "main");

		if (!empty($this->data)){

			if($answer_id == -1)
			{
				$question = $this->Asession->find('first',
					array
					(
						'conditions' => array('Question.id' => $question_id),
					)
				);
				$asession = $this->Asession->find('first',
					array
					(
						'conditions' => array('Asession.uniqueid' => $token),
					)
				);
				if($question['Question']['critical'] == 1)
				{
					$this->Asession->id = $asession['Asession']['id'];
					$this->Asession->set(array('result' => 0));
					$this->Asession->save();
					return;
				}
			}
			#error_log('got data'.print_r($this->data,true));

			if (empty($this->data['Question']['question_id'])){
				#error_log("question_id has not been supplied");
				$this->Session->setFlash("question_id has not been supplied");
				$this->redirect('/asessions/question/'.$this->data['Asession']['token'].'/'.$this->data['Question']['question_id']);
			}
			if (empty($this->data['Question']['answer_id'])){
				#error_log("answer_id has not been supplied");
				$this->Session->setFlash("Please supply an answer to the question.");
				$this->redirect('/asessions/question/'.$this->data['Asession']['token'].'/'.$this->data['Question']['question_id']);
			}
		}

		elseif (($token == false) &&  ($question_id == false) && ($answer_id == false)){
			$this->set('message', 'INVALID PATH: missing arguments');
			$this->header('HTTP/1.1 400 Bad Request');
			$this->render('index');
			return;
		}

		if (empty($this->data)){
			
			$this->data['Asession'] = array(
				'token'=> $token
			);
			
			$this->data['Question'] = array(
				'question_id'=>$question_id,
				'answer_id'=> $answer_id
			);

		}

		if ($this->_validate_token($this->data['Asession']['token'])){

			$this->Question->unbindModel(
				array('hasMany' => array('Asessionlog'))
			);
			$this->Question->Questiongroup->unbindModel(
				array('hasMany' => array('Asessionlog'))
			);
			$this->Question->Answer->unbindModel(
				array('hasMany' => array('Asessionresult'))
			);

			$question = $this->Question->findById($this->data['Question']['question_id']);
			$asession = $this->Asession->findById($this->asession_id);

			if ($this->_is_answer_correct() == true){
				$correct = 1;
			}else{
				$correct = 0;
			}
			
			

			/*
				add the log record
			*/

			$newSessionLog = array(
				'Asessionlog' => array(
					'asession_id' => $this->asession_id,
					'answer' => $question['Question']['id'],
					'correct' => $correct,
					'questiongroup_id' => 0,
					'question_id' => 0,
					'event_id' => 0,
					'message' => ''
					//'message' => 'Answer Given'
				),
			);

			$this->Asessionlog->save($newSessionLog);
			$this->_record_answers();
			unset($this->Asessionlog->id);

			if (($correct == 0) && ($question['Question']['required_correct'] == 1)){

				#$this->Session->setFlash("Answer supplied was incorrect.");
				$this->Session->write('Asession.answer_result', 'wrong');
				$this->redirect('/asessions/question/'.$this->data['Asession']['token'].'/'.$this->data['Question']['question_id']);

			}
			elseif (($correct == 0) && ($question['Question']['required_correct'] == 0)){

				#$this->Session->setFlash("Thank you for your answer.");
			
			}else{
		
				#$this->Session->setFlash("Your answer is correct.");
				$this->Session->write('Asession.answer_result', 'correct');
				$this->state($this->data['Asession']['token'], true, true);
	
			}

		}else{

			$this->redirect('/asessions/index');

		}

	}
	
	################
	# LOGICAL FLOW METHODS
	################

	function next(){

		$this->Asession->unbindModel(
			array('hasMany' => array('Asessionlog'))
		);

		$asession = $this->Asession->findById($this->asession_id);
		
		$this->Asession->bindModel(
			array('hasMany' => array('Asessionlog'))
		);

		$this->Questiongroup->unbindModel(
			array('hasMany' => array('Asessionlog'))
		);

		$this->Question->unbindModel(
			array('hasMany' => array('Asessionlog'))
		);

		$this->Question->Questiongroup->unbindModel(
			array('hasMany' => array('Asessionlog'))
		);

		$this->Question->Answer->unbindModel(
			array('hasMany' => array('Asessionresult'))
		);
;

		/*
			get the latest log for this asession to discover the state (might DRY this up a bit later)
		*/

		$asessionlog_rec = $this->Asessionlog->find('first',
			array(
				'conditions' => array('Asessionlog.asession_id' => $this->asession_id),
				'order' => array('Asessionlog.id DESC'),
			)
		);

		$current_state = 'invalid';
		$questiongroup = false;
		$question = false;

		/*
			If the record has no correct flag, no questiongroup id, no question id or answer id then it must 
			be an assessment session start log
		*/

		if (($asessionlog_rec['Asessionlog']['questiongroup_id'] == 0) && ($asessionlog_rec['Asessionlog']['question_id'] == 0) && ($asessionlog_rec['Asessionlog']['answer'] == 0) && ($asessionlog_rec['Asessionlog']['correct'] == 0)){
			
			#error_log('ASSESSMENT START');
			
			$check_questiongroups_complete = $this->check_questiongroups_complete($asession['Asession']['assessment_id']);

			if ($check_questiongroups_complete === true){

				#error_log('returned true so no questiongroups returned must be end of assessment');
				$current_state = 'complete';

			}else{

				#error_log('return next questiongroup');
				$questiongroup =  $this->Questiongroup->findById($check_questiongroups_complete);
				$current_state = 'questiongroup';

			}


		}

		/*
			If the record has questiongroup and no question or answer and does not have a "correct" value must be a question group start log
		*/

		elseif (($asessionlog_rec['Asessionlog']['questiongroup_id'] > 0) && ($asessionlog_rec['Asessionlog']['question_id'] == 0) && ($asessionlog_rec['Asessionlog']['answer'] == 0) && ($asessionlog_rec['Asessionlog']['correct'] == 0)){
			
			#error_log('QUESTION GROUP START');

			$this->Questiongroup->unbindModel(
				array('hasMany' => array('Asessionlog'))
			);

			$questiongroup = $this->Questiongroup->findById($asessionlog_rec['Asessionlog']['questiongroup_id']);

			// if the questiongroup has a question then ask the first one
			// if not we have to wait until they visit the questiongroup page and then mark the questiongroup complete.
			if (isset($questiongroup['Question'][0]['id'])){

				$question = $this->Question->findById($questiongroup['Question'][0]['id']);
				$current_state = 'question';
			
			}else{

				$current_state = 'questiongroup';

			}

		}

		/*
			If the question group id exists and has no question or answer and has a positive "correct" value then it must be a question group end or message only log
		*/

		elseif (($asessionlog_rec['Asessionlog']['questiongroup_id'] > 0) && ($asessionlog_rec['Asessionlog']['question_id'] == 0) && ($asessionlog_rec['Asessionlog']['answer'] == 0) && ($asessionlog_rec['Asessionlog']['correct'] == 1)){
			
			#error_log('QUESTION GROUP END');
			
			$check_questiongroups_complete = $this->check_questiongroups_complete($asession['Asession']['assessment_id']);

			if ($check_questiongroups_complete === true){

				#error_log('no questiongroup returned must be end of assessment');
				$current_state = 'complete';

			}else{

				$current_state = 'questiongroup';
				$questiongroup = $this->Questiongroup->findById($check_questiongroups_complete);


			}


		}

		/*
			If the record has a question id but no answer associated with it then it must be a Question asked log
		*/

		elseif (($asessionlog_rec['Asessionlog']['question_id'] > 0) && ($asessionlog_rec['Asessionlog']['answer'] == 0)){

			#error_log('QUESTION ASKED:'.$asessionlog_rec['Asessionlog']['id']);
			
			$question = $this->Question->find('first',
				array(
					'conditions' => array('Question.id' => $asessionlog_rec['Question']['id']),
					'recursive' => 2, 
				)
			);

			$current_state = 'question';

		}

		/*
			If the record has no question but has an answer id then it must be an answer to a question.
		*/
		
		elseif (($asessionlog_rec['Asessionlog']['question_id'] == 0) && ($asessionlog_rec['Asessionlog']['answer'] > 0)){

			#error_log('QUESTION ANSWER:'.$asessionlog_rec['Asessionlog']['id']);

			$prev_question_asked = $this->Question->find('first',
				array(
					'conditions' => array('Question.id' => $asessionlog_rec['Asessionlog']['answer']),
					'recursive' => 2, 
				)
			); 

			//##error_log("PREVIOUS QUESTION:".print_r($prev_question_asked, true));

			$current_state = 'question';

			if (($asessionlog_rec['Asessionlog']['correct'] == 1) || ($prev_question_asked['Question']['required_correct'] == 0)){

				#error_log('QUESTION ANSWERED CORRECTLY OR NO CORRECT ANSWER NEEDED'); 

				$asessionlog_qg_rec = $this->Asessionlog->find('first',
					array(
						'conditions' => array('Asessionlog.asession_id' => $this->asession_id, 'Asessionlog.questiongroup_id >' => 0),
						'order' => array('Asessionlog.id DESC'),
					)
				);

				#error_log('QuestionGroupID:'.$asessionlog_qg_rec['Asessionlog']['questiongroup_id']);

				$is_questiongroup_complete = $this->check_questiongroup_end($asessionlog_qg_rec['Asessionlog']['questiongroup_id']);

				if ($is_questiongroup_complete === true){

					$newSessionLog = array(
						'Asessionlog' => array(
							'asession_id' => $this->asession_id,
							'questiongroup_id' => $asessionlog_qg_rec['Asessionlog']['questiongroup_id'],
							'correct' => 1,
							'answer' => 0,
							'question_id' => 0,
							'event_id' => 0,
							'message' => ''
							//'message' => 'Question Group Complete'
						),

					);

					$this->Asessionlog->save($newSessionLog);
					unset($this->Asessionlog->id);

					$check_questiongroups_complete = $this->check_questiongroups_complete($asession['Asession']['assessment_id']);

					if ($check_questiongroups_complete === true){

						#error_log('no questiongroup returned must be end of assessment');
						$current_state = 'complete';
						$questiongroup = false;


					}else{

						$current_state = 'questiongroup';
						$questiongroup = $this->Questiongroup->findById($check_questiongroups_complete);

					}
					
					$question = false;

				}else{
					
					$current_state = 'question';
					$question = $this->Question->findById($is_questiongroup_complete);
					$questiongroup = false;

				}
			
			}else{

				#error_log('Question answered needs to be answered correctly and was not so we need to ask the same question again...');

				$question = $prev_question_asked;
				$questiongroup = false;
				$current_state = 'question';

			}
			
		}

		return array(
			'questiongroup'=> $questiongroup, 
			'question' => $question,
			'state' => $current_state
		);

	}

	function check_questiongroups_complete($assessment_id){

		/*
			Collect all the data for this assessment and check the assessions table for a reference
			to a correct questiongroup if no reference exists send them to start the questiongroup
		*/

		#error_log('checking assessment:'.$assessment_id);

		$assessment = $this->Assessment->findById($assessment_id);

		foreach ($assessment['Questiongroup'] as $questiongroup){

			#error_log('checking that the questiongroup is complete: '.$questiongroup['id'].'/'.$this->asession_id);

			$asessionlog_rec_qgroup = $this->Asessionlog->find('first',
				array(
					'conditions' => array(
						'Asessionlog.asession_id' => $this->asession_id,
						'Asessionlog.questiongroup_id' => $questiongroup['id'],
						'Asessionlog.correct' => 1
					)
				)
			);

			##error_log(print_r($asessionlog_rec_qgroup,true));

			if (empty($asessionlog_rec_qgroup)){
				#error_log('questiongroup NOT complete: '.$questiongroup['id']);
				return $questiongroup['id'];
			}

		}

		/*
			update asssessment session to be complete
		*/
		$this->Asession->id = $this->asession_id;
		$this->Asession->saveField('complete', 1);
		return true;

	}

	function check_questiongroup_end($questiongroup_id){

		#error_log('checking that the questiongroup is complete: '.$questiongroup_id);
		
		$this->Questiongroup->unbindModel(
			array('hasMany' => array('Asessionlog'))
		);

		$questiongroup = $this->Questiongroup->findById($questiongroup_id);

		foreach ($questiongroup['Question'] as $question){

			$asessionlog_rec_question = $this->Asessionlog->find('first',
				array(
					'conditions' => array(
						'Asessionlog.asession_id' => $this->asession_id,
						'Asessionlog.answer' => $question['id'],
					),
					'order' => array('Asessionlog.id DESC'),
				)
			);

			if (empty($asessionlog_rec_question)){

				#error_log('NO QUESTION RECORDED EXISTS YET: '.$question['id']);
				return $question['id'];

			}else{

				if ($question['required_correct'] == 0){

					continue;

				}else{

					if ($asessionlog_rec_question['Asessionlog']['correct'] == 0){
						return $question['id'];
					}

				}

			}
				
		}

		return true;

	}

	################
	# ANSWER RECORD METHODS
	################

	function _is_answer_correct(){

		$this->Question->unbindModel(
			array('hasMany' => array('Asessionlog'))
		);
		$this->Question->Questiongroup->unbindModel(
			array('hasMany' => array('Asessionlog'))
		);
		$this->Question->Answer->unbindModel(
			array('hasMany' => array('Asessionresult'))
		);

		$question = $this->Question->find('first',
			array(
				'conditions' => array('Question.id' => $this->data['Question']['question_id']),
				'recursive' => 2, 
			)
		);

		// These are currently database driven and are hardcoded here.
		switch ($question['Answertype']['answeraction_id']) {
		
			// 1  = store the result
			case 1:
				##error_log('Answer Action store: '.$question['Answertype']['answeraction_id']);
				return true;
			break;

			// 1  = Check the result against what should be correct.
			case 2:
				##error_log('Answer Action check: '.$question['Answertype']['answeraction_id']);
				return $this->_check_answer($question);
			break;		
		}

	}

	function _check_answer($question){
	
		/*
			Check to see if this is an ordered list
			If it is not we need to check if it is correct
		*/
		
		if ($question['Answertype']['Formtype']['name'] == 'order'){

			return $this->_check_correct_order($question);
		
		}else{
			
			// At this stage if the answers are to be multi-answer they must all be correct
			if (is_array($this->data['Question']['answer_id'])){

				##error_log('Checking Multi Answer...');

				$correct_answers = array();
				$incorrect_answers = array();

				foreach ($question['Answer'] as $answer){
					if ($answer['correct'] == 1){
						$correct_answers[] = $answer['id'];
					}else{
						$incorrect_answers[] = $answer['id'];
					}
				}

				##error_log('Incorrect answer array...'.print_r($incorrect_answers,true));

				$isCorrect = true;
				
				$array_difference = array_diff($correct_answers, $this->data['Question']['answer_id']);

				if (count($array_difference)) {
					##error_log('Some answers were not present in the correct list');
					$isCorrect = false;
				}
				
				foreach ($this->data['Question']['answer_id'] as $answer_id_given){

					##error_log('Checking that answer_id ('.$answer_id_given.') is in the incorrect_answers array');

					if (in_array($answer_id_given, $incorrect_answers) == true){
						##error_log('answer_id ('.$answer_id_given.') was present in the incorrect list');
						$isCorrect = false;
						break;
					}
				}

				return $isCorrect;
				
			}else{

				##error_log('Checking Single Answer...');

				foreach ($question['Answer'] as $answer){

					if (($answer['id'] == $this->data['Question']['answer_id']) && ($answer['correct'] == 1)){
						##error_log('answer is correct returning true');
						return true;
					}
				}

				##error_log('answer is not correct returning false');

				return false;

			}
		}

	}

	function _check_correct_order($question){

		$answers_in_order = $this->Answer->find('all',
			array(
				'conditions' => array('Answer.question_id' => $question['Question']['id']),
				'order' => array('Answer.rank'), 
			)
		);

		$array_index = 0;

		foreach ($answers_in_order as $ordered_answer){	

			if ($ordered_answer['Answer']['id'] != $this->data['Question']['answer_id'][$array_index]){
				##error_log('Match Failed at index #'.$array_index.' - '.$ordered_answer['Answer']['id'].'!='.$this->data['Question']['answer_id'][$array_index]);
				return false;
			}

			$array_index ++;

		}

		return true;

	}

	function _record_answers(){

		$newAsessionID = $this->Asessionlog->id;

		##error_log('newAsessionlogID:'.$newAsessionID);

		if (isset($this->data['Question']['answer_id'])){
			$the_answer_id = $this->data['Question']['answer_id'];
		}else{
			$the_answer_id = false;
		}

		if (is_array($the_answer_id)){
			
			##error_log('Storing Multi Answer');

			foreach ($this->data['Question']['answer_id'] as $answer_id){

				$newResultLog = array(
					'Asessionresult' => array(
						'asessionlog_id' => $newAsessionID,
						'answer_id' => $answer_id,
					)
				);

				$this->Asessionresult->save($newResultLog);
				
				##error_log('Storing Result for answer ID ('.$answer_id.'):'.$this->Asessionresult->id);
				unset($this->Asessionresult->id);

			}

		}else{

			##error_log('Storing Single Answer');

			if (isset($this->data['Question']['answer_text'])){
				$answer_text = $this->data['Question']['answer_text'];
				$answer_id = 0;
			}else{
				$answer_text = '';
				$answer_id = $this->data['Question']['answer_id'];
			}

			$newResultLog = array(
				'Asessionresult' => array(
					'asessionlog_id' => $this->Asessionlog->id,
					'answer_id' => $answer_id,
					'answer_text' => $answer_text,
				)
			);

			$this->Asessionresult->save($newResultLog);

		}
		
	}

	function _randomise_answers($questionArray){

		$new_answer_id_array = array();
		
		foreach ($questionArray['Answer'] as $answer){
			$new_answer_id_array[] = $answer['id'];
		}

		shuffle($new_answer_id_array);
		$newAnswerOrderArray = array();

		while (count($new_answer_id_array)){
			$new_answer_id = array_pop($new_answer_id_array);
			foreach ($questionArray['Answer'] as $answer){
				if ($answer['id'] == $new_answer_id){
					$newAnswerOrderArray[] = $answer;
				}
			}
		}
		
		return $newAnswerOrderArray;

	}

	################
	# AUTH / ASESSION METHODS
	################

	function _authenticate($assessment_id = 0, $password = ''){
		
		$assessment = $this->Assessment->findById($assessment_id);

		if ($assessment){

			if ($assessment['Assessment']['assessment_password'] != $password){

				#error_log('assessment password does not match');
				return false;


			}

		}else{

			#error_log('could not find assessment');
			return false;

		}

		return true;

	}

	function _gen_assessment_key(){

		$uniqueid = md5(uniqid());

		#error_log($uniqueid);

		$asession_rec = $this->Asession->find('first',
			array(
				'conditions' => array('Asession.uniqueid' => $uniqueid),
			)
		);

		if ($asession_rec){
			$this->_gen_assessment_key();
		}else{
			return $uniqueid;
		}

	}

	function _validate_auth_header(){

		/*
		<request>
		  <auth>
			<username>000000001</username>
			<password>test</password>
			<course_id>1</course_id>
			<assessment_id>1</assessment_id>
		  </auth>
		</request>
		*/

		if (empty($this->data['Request']['Auth']['username'])){
			#error_log('missing username component');
			return false;
		}
		elseif (empty($this->data['Request']['Auth']['password'])){
			#error_log('missing password component');
			return false;
		}
		elseif (empty($this->data['Request']['Auth']['assessment'])){
			#error_log('missing assessment_id component');
			return false;
		}
		elseif(empty($this->data['Request']['Auth']['course'])){
			#error_log('missing course_id component');
			return false;
		}else{
			#error_log('auth header complete');
			return true;
		}

	}

	function _validate_token($token){

		/*
		<request>
		  <token>2dd7b254cd99f3f3df3ba64be8104cb1</token>
		</request>
		*/

		#error_log('Validating Token:'.$token);

		$asession_rec = $this->Asession->find('first',
			array(
				'conditions' => array('Asession.uniqueid' => $token),
			)
		);

		if (!empty($asession_rec)){
			#error_log('valid session found');
			$this->asession_id = $asession_rec['Asession']['id'];
			return true;
		}else{
			#error_log('invalid assessment session');
			return false;
		}

	}

	function _has_student_number(){

		#error_log('Validating Token:'.$token);

		$asession_rec = $this->Asession->find('first',
			array(
				'conditions' => array('Asession.id' => $this->asession_id),
			)
		);

		if ($asession_rec['Asession']['student_number'] != ''){
			error_log('student number exists');
			return true;
		}else{
			error_log('has no student number');
			return false;
		}

	}
}
?>
